module App
    class TogglTreeModel < Qt::StandardItemModel
        #NewProjectItemText = "[New project]"
        #NewTaskItemText = "[New task]"
        NewProjectItemText = ""
        NewTaskItemText = ""

        signals 'datadropped(QString*, QStandardItem*)'
        signals 'refreshModelBegin(const QAbstractItemModel *)'
        signals 'refreshModelEnd(const QAbstractItemModel *)'

        slots 'resort1(const QModelIndex &, const QModelIndex &)'
        slots 'resort2(QStandardItem*)'
        slots :refreshModel, :stopAllTasks, :reload

        #alias_method :refreshModel, :reload
        #alias_method :stopAllTasks, :stop_all_tasks

        attr_reader :toggl

        def initialize(toggl)
            super()
            
            clear
            
            #setItemPrototype Qt::StandardItem.new
            #p itemPrototype

            setSortRole Qt::UserRole
            #Qt::Object.connect(self, SIGNAL('dataChanged(const QModelIndex &, const QModelIndex &)'),
            #        self, SLOT('resort1(const QModelIndex &, const QModelIndex &)'))
            Qt::Object.connect(self, SIGNAL('itemChanged(QStandardItem*)'),
                self, SLOT('resort2(QStandardItem*)'))

            @toggl = toggl
        end
    
        def clear()
            super()

            setColumnCount 4
            setHeaderData(0, Qt::Horizontal, Qt::Variant.new("Task"))
            setHeaderData(1, Qt::Horizontal, Qt::Variant.new("Start"))
            setHeaderData(2, Qt::Horizontal, Qt::Variant.new("Stop"))
            setHeaderData(3, Qt::Horizontal, Qt::Variant.new("Dur."))
        
            @clients = []
            @projects = []
            @tasks = []
        end
        

        private
#        def resort1(minx1, minx2)
#            puts "resort needed on: #{minx1.row},#{minx1.column} #{minx2.row},#{minx2.column}"
#            @projects.each { |p|
#                p.sortChildren 0, Qt::DescendingOrder
#            }
#        end
        def resort2(item)
            return unless item.is_a? App::Items::Task
            #puts "itemChanged: #{item} #{item.row},#{item.column}"
            item.parent.sortChildren 0, Qt::DescendingOrder
        end


        public
        def getRunningTask()
            @tasks.find { |item| item.started }
        end

        # actions
        def start_task(task)
            stop_all_tasks

            # If we work on a task daily, we should make a new task for each day.
            # Because I work nightly, the turn is at 6:00AM. -pallair
            mymidnight = Time.parse("6:00")
            mymidnight = mymidnight + (-24*60*60) if mymidnight > Time.now
            #puts "start: new task? #{Time.at(task.stop_ms/1000)}; Now:#{Time.now} TodayFrom:#{mymidnight}"
            # _(ha mar regi taszk es regebbi mint ma hajnali hat es mar elmult hat)  :)
            if task.stop_ms > 0 and task.stop_ms/1000 < mymidnight.to_i
                #puts "YES!"
                task = App::Items::Task.create(self, task.description, task.parent)
                addTask task
            end
            
            task.start!
        end

        def stopAllTasks; stop_all_tasks; end
        def stop_all_tasks
            rtask = getRunningTask and rtask.stop
        end

        def new_task(project, name, start = true)
            #puts "addTask", project, name
            item = App::Items::Task.create(self, name, project)
            addTask item
            item.start if start
            item
        end
        def new_project(client, name, billable)
            #puts "addProject", client, name, billable
            item = App::Items::Project.create self, name, billable, client
            addProject item
            item
        end
        def new_client(name)
            #parentitem ||= @pnt.invisibleRootItem
            item = App::Items::Client.create self, name
            addClient item
            item
        end

        def refreshModel; reload; end
        def reload
            emit refreshModelBegin(self)
            clear
            begin
                @toggl.clientlist.each { |client|
                    addClient App::Items::Client.new(client)
                }
                @toggl.projlist.each { |project|
                    addProject App::Items::Project.new(project) if App::Items::Project.valid? project
                }
                @toggl.tasklist.each { |task|
                    addTask App::Items::Task.new(task) if App::Items::Task.valid? task
                }
            # XXX ... move it into the controllers?
            rescue LoginError => e
                App::View::ErrorDialog.new($widget.view, e.to_s)
                App::Controller::Login.new($widget.view).exec and retry
            rescue CommunicationError => e
                App::View::ErrorDialog.new($widget.view, e.to_s)
                $widget.quit
            end
            emit refreshModelEnd(self)
        end


        def eachTask()
            @tasks.each { |task|
                yield task
            }
        end

        def eachClient()
            @clients.each { |client|
                yield client
            }
        end

        private
        def addClient(item)
            item.setDropEnabled false
            self.invisibleRootItem.appendRow [ item,
                App::Items::MyStandardItem.new,
                App::Items::MyStandardItem.new,
                App::Items::MyStandardItem.new ]
            @clients << item
        
            #newp = Qt::StandardItem.new CPTModel::NewProjectItemText
            #newp.setIcon KDE::Icon.new("appointment-new")
            #item.appendRow [ newp, MyStandardItem.new, MyStandardItem.new ]
        end
    
        def addProject(item)
            p = getparent(item)
            unless p
                puts "No Client for #{item.inspect}, skip"
                return
            end
            p.appendRow [ item,
                App::Items::MyStandardItem.new,
                App::Items::MyStandardItem.new,
                App::Items::MyStandardItem.new ]
            @projects << item
        
            #newp = Qt::StandardItem.new CPTModel::NewTaskItemText
            #newp.setIcon KDE::Icon.new("appointment-new")
            #item.appendRow [ newp, MyStandardItem.new, MyStandardItem.new ]
        end
    
        def addTask(item)
            item.setDropEnabled false
            current = @tasks.find { |task| not task.taken and task.description.to_s == item.description.to_s }
            head = true
            if current
                if Time.at(current.stop_ms/1000) < Time.at(item.stop_ms/1000) or item.stop_ms == 0
                    item.eatSameTask current
                    cleanItem current
                    current.parent.takeRow current.row
                else
                    current.addSameTask item
                    current.appendRow [ item, item.getChildItemWithStart, item.childitem_stop, item.getChildItemWithDuration ]
                    head = false
                end
            end
            if head
                unless getparent(item)
                    puts "NO PARENT FOR TASK #{item.inspect} ... skip"
                    return
                end
                getparent(item).appendRow [ item, item.getChildItemWithStart, item.childitem_stop, item.getChildItemWithDuration ]
                item.sametasks.each { |t|
                    item.appendRow [ t, t.getChildItemWithStart, t.childitem_stop, t.getChildItemWithDuration ]
                }
            end
            @tasks << item
        end

        public  # Items call thoose
        def _deleteClient(item)
            self.invisibleRootItem.removeRow item.row
            @clients.delete item
        end

        def _deleteProject(item)
            item.parent.removeRow item.row
            @projects.delete item
        end
        
        def _deleteTask(item)
            newhead = item.sametasks.first
            if newhead
                newhead.eatSameTask item
                newhead.deleteSameTask item
                cleanItem item
                getparent(newhead).appendRow [ newhead, 
                    newhead.getChildItemWithStart, newhead.childitem_stop,
                    newhead.getChildItemWithDuration ]
                newhead.sametasks.each { |t|
                    newhead.appendRow [ t, 
                        t.getChildItemWithStart, t.childitem_stop,
                        t.getChildItemWithDuration ]
                }
            elsif item.taken
                item.taken.deleteSameTask item
            end
            item.parent.removeRow item.row
            @tasks.delete item
            
            # XXX would be nicer with a signal
            resort2 newhead
        end
        
        
        # _(ha a KDE taskbar -on valtunk a programra, akkor ez nem mukodik, valami
        # bug van. always-on-top ablakba barmikor mukodik)
        def dropMimeData(mimedata, action, row, column, modelindex)
            puts "dropMimeData!"
        
            unless mimedata.hasText
                puts "invalid format"
                return false
            end
            if action == Qt::IgnoreAction
                puts "ignoreaction"
                return true
            end
            if column > 0
                puts "invalid column"
                return false
            end
            return unless modelindex.isValid
        
            #puts "dropped on item", itemFromIndex(modelindex).class.to_s
            emit datadropped(mimedata.text, itemFromIndex(modelindex))
        
            return true
        end
        def mimeTypes()
            types = []
            types << "text/plain"
            #types << "*/*"
            return types
        end
        def supportedDropActions()
            return Qt::CopyAction | Qt::MoveAction
        end
        
        
        private
        def cleanItem(item)
            # FIXME
            # What is the right solution to remove an Item's childs?
            # It works, but ugly!
            for i in 0...item.rowCount
                #            puts "take! #{i}"
                #            item.takeRow i
                for j in 0...item.columnCount
                    #p "child #{i}, #{j}"
                    item.takeChild i, j
                end
            end
            item.setRowCount 0
            raise "cleanItem failed" if item.hasChildren
        end

        def getparent(item)
            # Called when appending the Item to Parent.
        
            # alternativ bejarasa a StandardItem -nek
            #        for i in 0...self.invisibleRootItem.rowCount
            #            thisitem = self.invisibleRootItem.child i
            #            puts "getparent each!", thisitem
            #        end
        
            case item
            when App::Items::Client then return false
            when App::Items::Project then return @clients.find { |c| item.client_id == c.tid }
            when App::Items::Task then return @projects.find { |p| item.project_id == p.tid }
            end
            return false
        end
    end
end
